from utils import *
import traceback
import json
import time
# import websockets
import re
import random
import traceback
import asyncio
import requests
from PIL import Image
from io import StringIO, BytesIO
# from xiaoice import chat, chat_with_img, logging
from config import Config, gl
import threading
from ws4py.client.threadedclient import WebSocketClient
from pyadnmb.pyadnmb import Adnmb
import pymongo
import secrets
from tools import *
from utils_new.logger import logger
from xiaowei import tbp_bot

lock = threading.Lock()
ad = Adnmb()
last_nick = ""


class MessagesDB:
    def __init__(self):
        self.client = pymongo.MongoClient(secrets.SECRET_MONGO_URI)
        self.db_name = secrets.SECRET_MONGO_URI.split('/')[-1]
        self.db = self.client[self.db_name]
        self.col = self.db[Constants.MESSAGE_COL_NAME]
    
    def insert(self, msg: dict):
        auto_time_insert(self.col, msg)
    
    def find(self, *args, **kwargs) -> list:
        return find_many(self.col, *args, **kwargs)
    


def make_message(text: str):
    return json.dumps({
        'cmd': 'chat',
        'text': text
    })


def regular_functions(ws, text):
    response = None

    if response is None:
        for h_words in Config.help_words:
            for k_word in Config.keywords:
                if text == h_words + k_word or text == k_word + h_words:
                    response = Config.help_str

    if response is None:
        if re.match(r'>>No.[0-9]*', text) is not None:
            try:
                tid = int(text[5:])
                mds = ad.getThread(tid).getMarkdownAll(expand=True)
                lines = ""
                for m in mds:
                    lines = lines + m + "\n"
                lines = lines[:-1]
                response = lines
            except Exception as e:
                logger.error(e)
                response = "获取失败了啦！"
        elif text == '速报':
            lines = ""
            news = list(map(lambda x: x.getMarkdown(), ad.getForumThreads(fname='速报2')))
            for n in news:
                lines = lines + n + '\n'
            lines = lines[:-1]
            response = lines
        elif text.startswith('捕捉'):
            sp = text.split(' ')
            if not (len(sp) == 2 or len(sp) == 3):
                return False
            if len(sp) == 3:
                nick = sp[2]
                ball = sp[1]
            else:
                nick = sp[1]
                ball = Config.ball_default
            ball = ball.replace('球', '')
            if ball not in Config.balls:
                ball = Config.ball_default
            response = "使用%s球捕捉%s..." % (ball, nick)
            if roll(Config.balls[ball]):
                response = response + "捉到了%s！" % nick
            else:
                response = response + "没捉到，让%s跑了！" % nick

        for ball_ in Config.balls:
            nick = None
            sp = text.split(' ')
            if text.startswith(ball_ + '球') and (len(sp) == 2 or len(sp) == 1):
                if len(sp) == 2:
                    nick = text.split(' ')[-1]
                else:
                    nick = last_nick
            if nick is not None:
                response = "使用%s球捕捉%s..." % (ball_, nick)
                if roll(Config.balls[ball_]):
                    response = response + "捉到了%s！" % nick
                else:
                    response = response + "没捉到，让%s跑了！" % nick
        if text == '捕捉':
            nick = last_nick
            if nick is not None:
                response = "使用%s球捕捉%s..." % (Config.ball_default, nick)
                if roll(Config.balls[Config.ball_default]):
                    response = response + "捉到了%s！" % nick
                else:
                    response = response + "没捉到，让%s跑了！" % nick

    if response is not None:
        ws.send(json.dumps({
            'cmd': 'chat',
            'text': response
        }))
        return True
    return False


def random_functions(ws, text):
    response = ""
    if False and (re.match(r'!\[.*\](.*)', text) is not None):
        if len(str(re.match(r'!\[.*\](.*)', text)[0])) == len(text):
            url = text[text.index(']') + 2:-1]
            # 发送图片模式
            # 先保存JPG图片
            try:
                im = Image.open(BytesIO(requests.get(url).content)).convert("RGB")
                im.save(Config.image_temp)
            except Exception as e:
                logging.error('saving image:', str(e))
                return
            response = chat_with_img(Config.image_temp)
        else:
            return
    else:
        # response = parse_words(chat(text))
        response = tbp_bot.chat(text)
        if response is None:
            raise RuntimeError("No response")
    for f_word in Config.forbidden_words:
        if f_word in response:
            response = response.replace(f_word, ' *BEEP* ')
    ws.send(json.dumps({
        'cmd': 'chat',
        'text': response
    }))


class MyClient(WebSocketClient):
    db: MessagesDB = None
    def opened(self):
        self.send(json.dumps({
            "cmd": "join",
            "channel": Config.default_room,
            "clientName": "[Chatino客户端](http://chatino.chiro.work/)",
            "clientKey": "X7t4qkI5Lz+cext",
            'nick': Config.nickname,
            'password': Config.password
        }))
        gl.set_value('running', True)
        gl.set_value('silence', False)
        # 输出欢迎信息
        for w in Config.welcome_words:
            self.send(make_message(random.choice(w)))

    def closed(self, code, reason=None):
        gl.set_value('running', False)

    def send_text(self, text):
        data = make_message(text)
        logger.debug(f'<- {data}')
        self.send(data)

    def send_exit_text(self):
        # 输出退出信息
        for w in Config.exiting_words:
            self.send(make_message(random.choice(w)))

    def received_message(self, resp):
        if self.db is None:
            self.db = MessagesDB()

        global last_nick
        if not gl.get_value('running'):
            return
        try:
            logger.debug(f'-> {resp}')
        except UnicodeEncodeError:
            logger.debug(f'-> (len) {len(resp)}')
        try:
            resp = json.loads(str(resp))
        except Exception as e:
            logger.error(f"{resp}, {e}")
            return
        data = resp
        self.db.insert(data)
        # print(data)
        if not data['cmd'] == 'chat':
            return
        if len(data['text']) == 0:
            return
        if data['nick'] == Config.nickname:
            return
        if data['nick'] in Config.users_except:
            return
        text = data['text']
        if 'member' in data and data['member'] is True:
            is_silent = is_silence_me(text, lock)
            if is_silent is True:
                # 视奸模式~
                for w in Config.silent_words:
                    self.send(make_message(random.choice(w)))
                return
            if is_silent is False:
                for w in Config.active_words:
                    self.send(make_message(random.choice(w)))
        if gl.get_value('silence'):
            return
        if is_moving_me_to(text, lock) is False:
            lock.acquire()
            gl.set_value('running', False)
            lock.release()
            self.send_exit_text()
            th = threading.Thread(target=run)
            th.setDaemon(True)
            lock.acquire()
            gl.set_value('th', th)
            lock.release()
            self.close()
            return

        calling = is_calling_me(text)
        # 删去@小微这样的字眼
        text = text.replace('@' + Config.nickname + ', ', '')
        text = text.replace('@' + Config.nickname + '， ', '')
        text = text.replace('@' + Config.nickname + ' ', '')
        text = text.replace('@' + Config.nickname + ',', '')
        text = text.replace('@' + Config.nickname + '，', '')
        text = text.replace('@' + Config.nickname, '')
        # 删掉上文引用
        text_lines = text.split('\n')
        text_select = ""
        for line in text_lines:
            if (len(line) > 0 and line[0] != '>') or line.startswith('>>No.'):
                text_select = text_select + line + '\n'
        text_select = text_select[:-1]
        text = text_select
        # logger.info(f"text: {text}")

        try:
            if regular_functions(self, text) is True:
                return
            if calling or roll(Config.activity):
                # 判断是否直接发送图片
                random_functions(self, text)
        except Exception as e:
            logger.error(f"{e}")
            traceback.print_exc()
            for w in Config.error_words:
                self.send(make_message(random.choice(w)))
        last_nick = data['nick']


def run():
    try:
        ws = MyClient(Config.api)
        ws.connect()
        time.sleep(0.1)
        while gl.get_value('running') is True:
            time.sleep(0.1)
        # ws.send_exit_text()
        ws.close()
    except Exception:
        traceback.print_exc()
        th = threading.Thread(target=run)
        th.setDaemon(True)
        lock.acquire()
        gl.set_value('th', th)
        lock.release()


if __name__ == '__main__':
    # print(chat('我真的想你了诶'))
    run()
    # running = True
    # print(is_calling_me('小微滚粗'))
